iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
3
Modern Web

成為 Modern PHPer系列 第 18

Day 18:Stream 概述

  • 分享至 

  • xImage
  •  

前言

對於 PHP Stream 的概念網路上的資源甚少,儘管這是從 PHP 4.3 開始就存在的功能,卻極少見到有開發者會去使用這樣的 Feature(或是使用這樣的 Feature 但不自知)。

先定義「Stream」是怎麼樣的存在,有助於理解它的意義:

  • 有一個起點及一個終點
  • 在起點與終點之間傳輸數據,就是 Stream 的概念

起點與終點可以允許為

  • 本地端檔案系統
  • 網路資源:包括但不限於 HTTP 及 FTP
  • 標準串流介面:stdin, stdout, stderr
  • 壓縮資源:zip

詳細的列表可以參閱官方文件

Stream 的使用

事實上,我們時常會時用到 Stream,只是通常不自知。

舉例而言,file_get_content() 函式中所要求的參數就是 Stream,我們可以在裡面自由填入 http://file://(如果沒有填的話預設是 file://)以取得資源。

許多與「檔案操作」類似的函式也都是以流為基本型式:fopen(), fclose(), fgets(), fwrite(), fseek()

值得一提的是,includerequire 也會受到 stream 的影響,所以如果系統存在 LFI 的話是相當危險的(關於 LFI 與 Stream 我會再開一篇文章討論)

註:PHP 預設會將 allow_url_include 關閉,所以通常無法直接 include 一個遠端的 PHP 檔案造成 RCE。

Stream 的應用

常用的 php://

在 PHP 中內建了一系列的 php:// 的 Stream Protocal,可以利用這些 protocol 強化 PHP 的某些功能。

php://input

取得所有的 input 通常來源於 HTTP body,值得注意的是,由這個 Stream 取得的內容是 Raw Body,所以需要自行解析。

php://stdin

取得由標準輸入所進入的內容,類似於 C++ 中的 cin,通常用於取得 Command Line 時的輸入。

php://stdout

將內容輸出至標準輸出中,類似於 C++ 的 cout。值得注意的是它只能寫不能讀(也無法用 fseek() 尋址)

php://memory

將內容輸出至記憶體中,可用於測試時期或一些快取資料。值得注意的是記憶體是有限的,所以如果記憶體耗盡可能會產生無法開啟的錯誤。

php://temp

php://memory 相似,優先會將資料存入記憶體,但若記憶體空間不足會把資料寫進臨時檔案。

PUT、PATCH 及 DELETE method

PHP 存在一些超全域變數,然而隨著 HTTP 的演進,卻遲遲沒有增加 $_PUT$_PATCH 等變數。

即便到了 2019 的今天,如果要取得 PUT 或 PATCH method 的 request body,仍然要透過 Stream。

<?php

$body = file_get_contents('php://input');

// 在這邊拿到的 $body 會是 raw http body(如下所示),需要自行解析它
// $body = 'name=Vincent&age=25';

甚至如果要做到「用 PUT Method 上傳檔案」,也是用類似的做法(但是要注意的是 enctype=multipart/form-data 的解析問題)

PHP 官方文件中有對此進行解釋,但事實上它會無法使用如 $_FILES 等常用的上傳檔案處理方式。

後記

之後 Stream 應該會再開兩篇文章,說明如何建立自定義的 Stream 及如何使用 Filter。


上一篇
Day 17:測試淺談
下一篇
Day 19:自定義 Stream
系列文
成為 Modern PHPer30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言